export {};


declare global {
  interface IArrayGroup<T> {
    key: string;
    info: T;
    items: Array<T>;
  }
  /**扩展数组、列表实例函数 */
  interface Array<T> {
    /**
     * [数组、列表]按(多个)属性排序
     * @param keys 属性列表
     * ```typescript
     * [{a:1,b:2},{a:2,b:1}].order("a"); //output:[{a:1,b:2},{a:2,b:1}]
     * [{a:1,b:2},{a:2,b:1}].order("a desc"); //output:[{a:2,b:1},{a:1,b:2}]
     * [{a:1,b:2},{a:2,b:1}].order(["a","b"]); //output:[{a:1,b:2},{a:2,b:1}]
     */
    order: (keys?: Array<string> | string) => Array<T>;
    /**
     * [数组、列表]按(多个)属性分组
     * @param keys 属性列表
     * ```typescript
     * [{a:1,b:2},{a:2,b:1}].group("a"); //output:[{key:"1",info:{a:1,b:2},items:[{a:1,b:2}]},{key:"2",info:{a:2,b:1},items:[{a:2,b:1}]}]
     * [{a:1,b:2},{a:2,b:1}].group(["a","b"]); //output:[{key:"1-2",info:{a:1,b:2},items:[{a:1,b:2}]},{key:"2-1",info:{a:2,b:1},items:[{a:2,b:1}]}]
     * ["a","b","a"].group(); //output:[{key:"a",info:"a",items:["a","a"]},{key:"b",info:"b",items:["b"]}]
     * ["a","b","a"].group("length"); //output:[{key:"1",info:"a",items:["a","b"]}]
     */
    group: (keys: Array<string> | string) => Array<IArrayGroup<T>>;
    /**
     * [数组、列表]按(多个)属性去重
     * @param keys 属性列表
     * ```typescript
     * [{a:1,b:2},{a:2,b:1}].distinct("a"); //output:[{a:1,b:2},{a:2,b:1}]
     * [{a:1,b:2},{a:2,b:1}].distinct("a,b"); //output:[{a:1,b:2},{a:2,b:1}]
     * ["a","b","a"].distinct(); //output:["a","b"]
     * ["a","b","a"].distinct("length"); //output:["a"]
     * [1,2,3,1].distinct(); //output:[1,2,3]
     */
    distinct: (keys?: Array<string> | string) => Array<T>;
    /**
     * [数组、列表]按(多个)属性获取并集
     * @param list2 数据列表
     * @param keys 属性列表
     * ```typescript
     * [{a:1,b:2},{a:2,b:1}].union([{a:2,b:1},{a:3,b:1}],"a"); //output:[{a:1,b:2},{a:2,b:1},{a:3,b:1}]
     * ["a","b","a"].union(["a","c"],"length"); //output:["a","b","c"]
     * [1,2,3,1].union([1,3]); //output:[1,2,3]
     */
    union: (list2: Array<T>, keys?: Array<string> | string) => Array<T>;
    /**
     * [数组、列表]按(多个)属性获取交集
     * @param list2 数据列表
     * @param keys 属性列表
     * ```typescript
     * [{a:1,b:2},{a:2,b:1}].inter([{a:2,b:1},{a:3,b:1}],"a"); //output:[{a:2,b:1}]
     * [1,2,3,1].inter([1,3]); //output:[1,3]
     */
    inter: (list2: Array<T>, keys?: Array<string> | string) => Array<T>;
    /**
     * [数组、列表]按(多个)属性获取差集
     * @param list2 数据列表
     * @param keys 属性列表
     * ```typescript
     * [{a:1,b:2},{a:2,b:1}].differ([{a:2,b:1},{a:3,b:1}],"a"); //output:[{a:1,b:2},{a:3,b:1}]
     * [1,2,3,1].differ([1,3]); //output:[2]
     */
    differ: (list2: Array<T>, keys?: Array<string> | string) => Array<T>;
    /**
     * [数组、列表]获取(多个)属性重复的索引组
     * @param keys 属性列表
     * ```typescript
     * [{a:1,b:2},{a:2,b:1},{a:1,b:2}].getRepeatIndex("a"); //output:[0,2]
     * ["a","b","a"].getRepeatIndex(); //output:[0,2]
     */
    getRepeatIndex: (keys?: Array<string> | string) => Array<number>;
    /**
     * [数组、列表]获取(多个)属性重复的项目组
     * @param keys 属性列表
     * ```typescript
     * [{a:1,b:2},{a:2,b:1},{a:1,b:2}].getRepeat("a"); //output:[{a:1,b:2},{a:1,b:2}]
     * ["a","b","a"].getRepeat(); //output:["a","a"]
     * [1,2,3,1].getRepeat(); //output:[1]
     */
    getRepeat: (keys?: Array<string> | string) => Array<T>;
    /**
     * [数组、列表]转换成索引访问器
     * ```typescript
     * ["a","b","c"].toRecord(); //output:{0:"a",1:"b",2:"c"}
     */
    toRecord: () => Record<string, T>;
    /**
     * [数组、列表]转换成Map
     * ```typescript
     * ["a","b","c"].toMap(); //output:{"0" => "a", "1" => "b", "2" => "c"}
     * [{a:1,b:2},{a:2,b:1}].toMap(); //output:{"0" => {a:1,b:2}, "1" => {a:2,b:1}}
     */
    toMap: () => Map<string, T>;
    /**
     * [数组、列表]清空数据
     * ```typescript
     * ["a","b","c"].clear(); //output:[]
     */
    clear: () => void;
  }
  /**扩展数组、列表静态函数 */
  interface ArrayConstructor {
    /**
     * 指定长度创建数组
     * @param len 长度
     * ```typescript
     * Array.create(3); //output:[0,1,2]
     */
    create: (len: number) => Array<number>;
    /**
     * [数组、列表]数据从索引访问器转换来
     * @param record 索引访问器
     * ```typescript
     * Array.fromRecord({0:"a",1:"b",2:"c"}); //output:["a","b","c"]
     * Array.fromRecord({"a":{a:1,b:2},"b":{a:2,b:1}}); //output:[{a:1,b:2},{a:2,b:1}]
     */
    fromRecord: <T>(record: Record<any, T>) => Array<T>;
    /**
     * [数组、列表]数据从Map转换来
     * @param map Map
     * ```typescript
     * Array.fromMap(new Map("a"=>{a:1,b:"11"},"b"=>{a:2,b:"22"})); //output:[{a:1,b:"11"},{a:2,b:"22"}]
     */
    fromMap: <T>(map: Map<any, T>) => Array<T>;
  }
}

/**是否纯对象 */
const isPureObj = (o: any) => {
  const type = Object.prototype.toString.call(o);
  return type === "[object Object]";
};
/**判断数组是二维列表 */
const isList = (list: Array<any>) => list.every(isPureObj);
/**获取属性列表 */
const getKeys = (keys?: Array<string> | string) => {
  if (!keys) return [];
  const ks = keys instanceof Array ? keys : keys.split(",");
  const mks = [...new Set(ks)].map((x) => x.replace(/^\s+/, ""));
  return mks.map((x) => x.replace(/\s+$/, "")).filter((x) => !!x);
};
/**获取字符串Unicode值总和 */
const getCode = (str: string) => {
  const arr = str.split("");
  const codes = arr.map((x, i: number) => str.charCodeAt(i));
  return codes.reduce((a: number, b: number) => a + b);
};
/**获取列比较器 */
const getComparator = (list: Array<any>, key: string = "") => {
  const cols = key ? list.map((x) => x[key]) : list;
  const types = cols.map((x) => typeof x);
  let asc, desc, ascM, descM;
  if (types.every((x) => x == "boolean")) {
    ascM = (a: any, b: any) => Number(a) - Number(b);
    descM = (a: any, b: any) => Number(b) - Number(a);
    asc = (a: any, b: any) => Number(a[key]) - Number(b[key]);
    desc = (a: any, b: any) => Number(b[key]) - Number(a[key]);
  } else if (types.every((x) => x == "number")) {
    ascM = (a: any, b: any) => a - b;
    descM = (a: any, b: any) => b - a;
    asc = (a: any, b: any) => a[key] - b[key];
    desc = (a: any, b: any) => b[key] - a[key];
  } else if (types.every((x) => x == "string")) {
    ascM = (a: any, b: any) => getCode(a) - getCode(b);
    descM = (a: any, b: any) => getCode(b) - getCode(a);
    asc = (a: any, b: any) => getCode(a[key]) - getCode(b[key]);
    desc = (a: any, b: any) => getCode(b[key]) - getCode(a[key]);
  } else {
    ascM = (a: any, b: any) =>
      getCode(JSON.stringify(a)) - getCode(JSON.stringify(b));
    descM = (a: any, b: any) =>
      getCode(JSON.stringify(b)) - getCode(JSON.stringify(a));
    asc = (a: any, b: any) =>
      getCode(JSON.stringify(a[key])) - getCode(JSON.stringify(b[key]));
    desc = (a: any, b: any) =>
      getCode(JSON.stringify(b[key])) - getCode(JSON.stringify(a[key]));
  }
  return { asc, desc, ascM, descM };
};
/**两端去空格 */
const trimStr = (str: string) => str.replace(/^\s+/, "").replace(/\s+$/, "");
/**两对象属性集是否相等 */
const isEqual = (x: any, y: any, keys?: Array<string> | string) => {
  if (!isPureObj(x) || !isPureObj(y)) return x == y;
  let ps = getKeys(keys);
  if (!ps.length) ps = Object.keys({ ...x, ...y });
  return ps
    .map((p) => ({ x: x[p] || p, y: y[p] || p }))
    .every((o) => o.x == o.y);
};
/**[数组、列表]按[多个]属性排序 */
Array.prototype.order = function (keys?: Array<string> | string) {
  const list = this.slice(0) as Array<any>;
  const ps = getKeys(keys);
  if (!isList(list)) {
    const c = getComparator(list);
    const [p, o] = ps[ps.length - 1].split(" ").map(trimStr);
    const fn = /^desc$/i.test(o || p) ? c.descM : c.ascM;
    return list.sort(fn);
  }
  for (let i = 0; i < ps.length; i++) {
    const [p, o] = ps[i].split(" ").map(trimStr);
    const c = getComparator(list, p);
    const fn = /^desc$/i.test(o) ? c.desc : c.asc;
    list.sort(fn);
  }
  return list;
};
/**[数组、列表]按[多个]属性分组 */
Array.prototype.group = function (keys: Array<string> | string) {
  const list = this as Array<any>;
  if (isList(list)) {
    const props = getKeys(keys);
    const gVals = list.map((x) => {
      const o: Record<string, any> = {};
      props.forEach((y) => (o[y] = x[y]));
      return o;
    });
    const groups = gVals.distinct(props);
    return groups.map((x) => {
      const info = x;
      const key = props.map((y) => `${x[y]}`).join("-");
      const items = list.filter((y) => isEqual(x, y, props)) || [];
      return { key, info, items } as IArrayGroup<any>;
    });
  } else {
    return list.map((x) => {
      const key = `${x}`;
      const info = x;
      const items = [x];
      return { key, info, items } as IArrayGroup<any>;
    });
  }
};
/**[数组、列表]按[多个]属性去重 */
Array.prototype.distinct = function (keys?: Array<string> | string) {
  const list = this as Array<any>;
  const map = new Map();
  const ks = getKeys(keys);
  const getProp = (o: any) => {
    if (!ks.length || ks.length < 1) return JSON.stringify(o);
    return ks.map((x) => JSON.stringify(o[x] || x)).join("-");
  };
  if (!isList(list)) return [...new Set(list)];
  return list.filter((x) => {
    const p = getProp(x);
    const has = map.has(p);
    return !has && map.set(p, x);
  });
};
/**[数组、列表]按[多个]属性获取并集 */
Array.prototype.union = function (
  list2: Array<any>,
  keys?: Array<string> | string
) {
  const list1 = this as Array<any>;
  const list = list1.concat(list2);
  return list.distinct(keys);
};
/**[数组、列表]按[多个]属性获取交集 */
Array.prototype.inter = function (
  list2: Array<any>,
  keys?: Array<string> | string
) {
  const list1 = this as Array<any>;
  //获取两列表的并集
  const list = list1.union(list2, keys);
  //并集中取两列表中都存在的
  return list.filter((x) => {
    const in1 = list1.some((y) => isEqual(x, y, keys));
    const in2 = list2.some((y) => isEqual(x, y, keys));
    return in1 && in2;
  });
};
/**[数组、列表]按[多个]属性获取差集 */
Array.prototype.differ = function (
  list2: Array<any>,
  keys?: Array<string> | string
) {
  const list1 = this as Array<any>;
  //获取两列表的并集
  const list = list1.union(list2, keys);
  //并集中取两列表中都存在的
  return list.filter((x) => {
    const in1 = list1.some((y) => isEqual(x, y, keys));
    const in2 = list2.some((y) => isEqual(x, y, keys));
    return (in1 && !in2) || (in2 && !in1);
  });
};
/**[数组、列表]获取(多个)属性重复的索引组 */
Array.prototype.getRepeatIndex = function (keys?: Array<string> | string) {
  const list = this as Array<any>;
  const result: Array<number> = [];
  if (isList(list)) {
    const ks = getKeys(keys);
    const getProp = (o: any) => {
      if (!ks.length || ks.length < 1) return JSON.stringify(o);
      return ks.map((x) => JSON.stringify(o[x] || x)).join("-");
    };
    for (let i = 0; i < list.length; i++) {
      const item1 = list[i];
      for (let j = i + 1; j < list.length; j++) {
        const item2 = list[j];
        if (getProp(item1) == getProp(item2)) {
          if (!result.some((x) => x == i)) result.push(i);
          result.push(j);
        }
      }
    }
  } else {
    for (let i = 0; i < list.length; i++) {
      for (let j = i + 1; j < list.length; j++) {
        if (list[i] == list[j]) {
          if (!result.some((x) => x == i)) result.push(i);
          result.push(j);
        }
      }
    }
  }
  return result;
};
/**[数组、列表]获取(多个)属性重复的项目组 */
Array.prototype.getRepeat = function (keys?: Array<string> | string) {
  const list = this as Array<any>;
  const indexs = this.getRepeatIndex(keys);
  return indexs.map((x) => list[x]);
};
/**[数组、列表]转换成索引访问器 */
Array.prototype.toRecord = function () {
  const list = this as Array<any>;
  const map: any = {};
  list.forEach((x, i: number) => (map[`${i}`] = x));
  return map;
};
/**[数组、列表]数据从索引访问器转换来 */
Array.fromRecord = function (record: Record<any, any>) {
  return Object.values(record);
};

/**[数组、列表]转换成索引访问器 */
Array.prototype.toMap = function () {
  const list = this as Array<any>;
  const map = new Map<string, any>();
  list.forEach((x, i: number) => map.set(`${i}`, x));
  return map;
};
/**[数组、列表]清空数据 */
Array.prototype.clear = function () {
  while (this.length) this.pop();
};
/**[数组、列表]数据从索引访问器转换来 */
Array.fromMap = function (map: Map<any, any>) {
  const list: Array<any> = [];
  map.forEach((x) => list.push(x));
  return list;
};
/**指定长度创建数组 */
Array.create = function (len: number) {
  return new Array(len).fill("").map((x, i: number) => i + 1);
};
